//@author A0121492M
import java.util.ArrayList;
import java.util.Collections;

public class Logic {

	public static ArrayList<Task> loadedData = Storage.loadedData;
	public static ArrayList<Command> commandHistory = new ArrayList<Command>();
	public static int lastCommand = -1;

	public static void saveData() {
		Storage.loadedData = loadedData;
		Storage.saveData();
	}

	public static ExecutionReply executeCommand(Command command)
			throws TaskNotFoundException, PopupClosedException, 
			NotUniqueException, ActionUnavailableException, InvalidInputException {
		assert (command instanceof AddCommand || command instanceof EditCommand
				|| command instanceof DeleteCommand || command instanceof ViewCommand 
				|| command instanceof ListCommand || command instanceof SearchboxCommand
				|| command instanceof DoneCommand || command instanceof UndoCommand
				|| command instanceof RedoCommand || command instanceof HelpCommand 
				|| command instanceof ExitCommand);
		return command.execute();
	}
	
	public static int findIndexByTitle(String taskTitle) 
			throws TaskNotFoundException, NotUniqueException {		
		int index = -1;
		ArrayList<Task> NotUniqueTasks = new ArrayList<Task>();
		for (int i = 0; i < loadedData.size(); i++) {
			String titleInList = loadedData.get(i).title;
			if (taskTitle.equalsIgnoreCase(titleInList)) {
				if (index == -1) {
					index = i;
				} else {
					if (NotUniqueTasks.size() > 0) {
						NotUniqueTasks.add(loadedData.get(i));
					} else {
						NotUniqueTasks.add(loadedData.get(index));
						NotUniqueTasks.add(loadedData.get(i));
					}
				}
			}
		}
		if (NotUniqueTasks.size() > 0) {
			throw new NotUniqueException(NotUniqueTasks);
		}
		return index;
	}
	
	public static ArrayList<Task> filterTasks(Task taskfilter) {
		ArrayList<Task> filteredList = new ArrayList<Task>();
		Task itask;
		int filtersPassed;
		int totalFilters = determineFilters(taskfilter);

		for (int i = 0; i < loadedData.size(); i++) {
			itask = loadedData.get(i);
			filtersPassed = 0;
			if (taskfilter.title != null && itask.title != null) {
				if (itask.title.toLowerCase().contains(taskfilter.title.toLowerCase())) {
					filtersPassed++;
				}
			}
			if (taskfilter.place != null && itask.place != null) {
				if (itask.place.toLowerCase().contains(taskfilter.place.toLowerCase())) {
					filtersPassed++;
				}
			}
			if (taskfilter.description != null && itask.description != null) {
				if (itask.description.toLowerCase().contains(taskfilter.description.toLowerCase())) {
					filtersPassed++;
				}
			}
			if (taskfilter.project != null && itask.project != null) {
				if (itask.project.toLowerCase().contains(taskfilter.project.toLowerCase())) {
					filtersPassed++;
				}
			}
			if ((taskfilter.startTime != null || taskfilter.endTime != null)
					&& (itask.startTime != null || itask.endTime != null)) {
				if (filterTimeIsPassed(taskfilter, itask)) {
					filtersPassed++;
				}
			}

			if (filtersPassed == totalFilters) {
				filteredList.add(itask);
			}
		}
		Collections.sort(filteredList);
		return filteredList;
	}
	
	private static int determineFilters(Task taskfilter) {
		int totalFilters = 0;
		if (taskfilter.title != null) {
			totalFilters++;
		}
		if (taskfilter.place != null) {
			totalFilters++;
		}
		if (taskfilter.description != null) {
			totalFilters++;
		}
		if (taskfilter.project != null) {
			totalFilters++;
		}
		if (taskfilter.startTime != null || taskfilter.endTime != null) {
			totalFilters++;
		}
		return totalFilters;
	}
	
	private static boolean filterTimeIsPassed(Task taskfilter, Task itask) {
		if (taskfilter.startTime == null && taskfilter.endTime == null) {
			// if no times specified, all tasks match this filter
			return true;
		} else if (taskfilter.startTime != null && taskfilter.endTime == null) {
			if (itask.startTime == null && itask.endTime == null) {
				// should not match unscheduled tasks
				return false;
			} else if (itask.startTime != null && itask.endTime == null) {
				if (taskfilter.startTime.compareTo(itask.startTime) <= 0) {
					return true;
				}
			} else if (itask.startTime == null && itask.endTime != null) {
				if (taskfilter.startTime.compareTo(itask.endTime) <= 0) {
					return true;
				}
			} else if (itask.startTime != null && itask.endTime != null) {
				if (taskfilter.startTime.compareTo(itask.endTime) <= 0) {
					return true;
				}
			}
		} else if (taskfilter.startTime == null && taskfilter.endTime != null) {
			if (itask.startTime == null && itask.endTime == null) {
				// should not match unscheduled tasks
				return false;
			} else if (itask.startTime != null && itask.endTime == null) {
				if (taskfilter.endTime.compareTo(itask.startTime) >= 0) {
					return true;
				}
			} else if (itask.startTime == null && itask.endTime != null) {
				if (taskfilter.endTime.compareTo(itask.endTime) >= 0) {
					return true;
				}
			} else if (itask.startTime != null && itask.endTime != null) {
				if (taskfilter.endTime.compareTo(itask.startTime) >= 0) {
					return true;
				}
			}
		} else if (taskfilter.startTime != null && taskfilter.endTime != null) {
			if (itask.startTime == null && itask.endTime == null) {
				// should not match unscheduled tasks
				return false;
			} else if (itask.startTime != null && itask.endTime == null) {
				if (taskfilter.startTime.compareTo(itask.startTime) <= 0 &&
						taskfilter.endTime.compareTo(itask.startTime) >= 0) {
					return true;
				}
			} else if (itask.startTime == null && itask.endTime != null) {
				if (taskfilter.startTime.compareTo(itask.endTime) <= 0 &&
						taskfilter.endTime.compareTo(itask.endTime) >= 0) {
					return true;
				}
			} else if (itask.startTime != null && itask.endTime != null) {
				if ((taskfilter.startTime.compareTo(itask.startTime) <= 0 && 
						taskfilter.endTime.compareTo(itask.startTime) >= 0)
						|| 
						(taskfilter.startTime.compareTo(itask.endTime) <= 0 && 
						taskfilter.endTime.compareTo(itask.endTime) >= 0)) {
					return true;
				}
			}
		}
		return false;
	}
	
	public static ArrayList<Task> findTasksByKeyword(String keyword) 
			throws TaskNotFoundException {
		ArrayList<Task> hits = new ArrayList<Task>();
		for (int i = 0; i < loadedData.size(); i++) {
			Task task = loadedData.get(i);
			keyword = keyword.toLowerCase();
			if (task.containsKeyword(keyword)) {
				hits.add(task);
			}
		}
		return hits;
	}
	
	public static void checkIfPopupClosed(Task task)
			throws PopupClosedException {
		if (task == null) {
			throw new PopupClosedException();
		}
	}
	
	public static void updateCommandHistory(Command command) {
		if (lastCommand < commandHistory.size() - 1) {
			commandHistory.removeAll(commandHistory.subList(lastCommand+1, commandHistory.size()));
		}
		commandHistory.add(command);
		lastCommand++;
	}
}
